﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceProcess;
using System.Configuration.Install;
using System.Configuration;
using System.Reflection;

namespace PTA.App
{
    /// <summary>
    /// Windows服务的基类,通过使用这个类作为基类,就可以在安装服务时,指定服务的名称,而不使用在开发时默认的名称.这个基类通过在安装时的参数中指定服务名称,在安装时传递给安装程序.
    /// <para>
    /// 安装示例(不重写ServiceName): InstallUtil /ServiceName=MyService App.exe 
    /// </para>
    /// <para>
    /// 卸载示例(不重写ServiceName): InstallUtil /u /ServiceName=MyService App.exe
    /// </para>
    /// <para>
    /// 参数：ServiceName 服务名称
    /// </para>
    /// <para>
    /// 参数：DisplayName 服务显示名称
    /// </para>
    /// <para>
    /// 参数：ServiceAccount 服务系统账户(默认LocalService)
    /// </para>
    /// <para>
    /// 参数: ServiceStartType 服务启动类型
    /// </para>
    /// <para>
    /// 参数：ServicePassword 服务用户密码
    /// </para>
    /// <para>
    /// 参数：ServiceUsername 服务用户名 
    /// </para>
    /// </summary>
    [System.ComponentModel.Description("子类不需要写【任何】代码，只需要实现这个类即可。")]
    public class ServiceInstaller : System.Configuration.Install.Installer
    {
        private System.ServiceProcess.ServiceProcessInstaller spi;
        private System.ServiceProcess.ServiceInstaller si;

        /// <summary>
        /// 必需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary> 
        /// 清理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源，为 true；否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }

            base.Dispose(disposing);
        }

        /// <summary>
        /// 设计器支持所需的方法 - 不要
        /// 使用代码编辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            this.spi = new System.ServiceProcess.ServiceProcessInstaller();
            this.si = new System.ServiceProcess.ServiceInstaller();
            // 
            // spi
            // 
            this.spi.Password = null;
            this.spi.Username = null;
            // 
            // ServiceInstaller
            // 
            this.Installers.AddRange(new System.Configuration.Install.Installer[] {
            this.spi,
            this.si});
            this.BeforeInstall += new System.Configuration.Install.InstallEventHandler(this.ServiceInstaller_BeforeInstall);
            this.BeforeUninstall += new System.Configuration.Install.InstallEventHandler(this.ServiceInstaller_BeforeUninstall);

        }

        /// <summary>
        /// 默认构造函数
        /// </summary>
        public ServiceInstaller()
        {
            InitializeComponent();
        }

        void ServiceInstaller_BeforeUninstall(object sender, InstallEventArgs e)
        {
            this.si.ServiceName = ServiceName;
            this.si.DisplayName = ServiceName;

            this.spi.Account = this.Account;
            this.spi.Password = this.Password;
            this.spi.Username = this.Username;
        }

        void ServiceInstaller_BeforeInstall(object sender, InstallEventArgs e)
        {
            this.spi.Account = this.Account;
            this.spi.Password = this.Password;
            this.spi.Username = this.Username;

            this.si.ServiceName = ServiceName;
            this.si.DisplayName = DisplayName;
            this.si.StartType = StartType;
        }

        /// <summary>
        /// 获取服务名称,使用可选择参数名称为ServiceName的参数来指定服务的名称,这个属性可以在子类中重写.
        /// <para>
        /// 例1,直接给出名称: return "MyService";
        /// </para>
        /// <para>
        /// 例2,使用配置文件:return ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location).AppSettings.Settings["ServiceName"].Value;
        /// </para>
        /// <para>
        /// 例3,使用可选参数:return this.Context.Parameters["SrvName"];
        /// </para>
        /// </summary>
        public virtual string ServiceName
        {
            get
            {
                string result = GetParameterValue("ServiceName");
                if (string.IsNullOrWhiteSpace(result))
                {
                    throw new Exception("服务名称不能为空");
                }
                return result;
            }
        }

        /// <summary>
        /// 获取服务友好名称,使用可选择参数名称为DisplayName的参数来指定服务的名称,这个属性可以在子类中重写.
        /// <para>
        /// 如果没有指定这个参数,则使用服务名称
        /// </para>
        /// <para>
        /// 例1,直接给出名称: return "DisplayName";
        /// </para>
        /// <para>
        /// 例2,使用配置文件:return ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location).AppSettings.Settings["DisplayName"].Value;
        /// </para>
        /// <para>
        /// 例3,使用可选参数:return this.Context.Parameters["DisplayName"];
        /// </para>
        /// </summary>
        public virtual string DisplayName
        {
            get
            {
                return GetParameterValue("DisplayName") ?? ServiceName;
            }
        }

        /// <summary>
        /// 运行这个服务的用户(默认:LocalSystem)
        /// </summary>
        public virtual ServiceAccount Account
        {
            get
            {
                string account = GetParameterValue("ServiceAccount");
                if (!string.IsNullOrWhiteSpace(account))
                {
                    return (ServiceAccount)Enum.Parse(typeof(ServiceAccount), account, true);
                }
                return ServiceAccount.LocalService;
            }
        }

        /// <summary>
        /// 用户密码(默认:null)
        /// </summary>
        public virtual string Password
        {
            get
            {
                return GetParameterValue("ServicePassword");
            }
        }

        /// <summary>
        /// 用户名(默认:null)
        /// </summary>
        public virtual string Username
        {
            get
            {
                return GetParameterValue("ServiceUsername");
            }

        }

        /// <summary>
        /// 服务的启动方式(默认:Automatic)
        /// </summary>
        public virtual ServiceStartMode StartType
        {
            get
            {
                string starttype = GetParameterValue("ServiceStartType");
                if (!string.IsNullOrWhiteSpace(starttype))
                {
                    return (ServiceStartMode)Enum.Parse(typeof(ServiceStartMode), starttype, true);
                }
                return ServiceStartMode.Automatic;
            }
        }

        private string GetParameterValue(string name)
        {
            if (this.Context.Parameters.ContainsKey(name))
            {
                return this.Context.Parameters[name];
            }
            Configuration config = ConfigurationManager.OpenExeConfiguration(this.GetType().Assembly.Location);
            if (config != null && config.AppSettings.Settings[name] != null)
            {
                return config.AppSettings.Settings[name].Value;
            }
            return null;
        }

    }
}
